home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
uupc11ys.zip
/
LIB
/
HOSTABLE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-10
|
26KB
|
678 lines
/*
h o s t a b l e . c
Remote host table routines for UUPC/extended
Copyright (C) 1989, 1990 by Andrew H. Derbyshire
See file README.SCR for restrictions on re-distribution.
History:
18 Mar 1990 Create hostable.c from router.c ahd
Move code to generate localdomain to here ahd
22 Apr 90 Perform check for full host name before examining
name without domain. ahd
29 Jul 90 Only load host table based on first six characters
of host name. ahd
*/
/*
* $Id: HOSTABLE.C 1.5 1993/04/11 00:32:29 ahd Exp $
*
* $Log: HOSTABLE.C $
* Revision 1.5 1993/04/11 00:32:29 ahd
* Global edits for year, TEXT, etc.
*
* Revision 1.4 1993/04/04 04:57:01 ahd
* Trap existence of local host name in SYSTEMS file
*
* Revision 1.3 1992/12/18 12:05:57 ahd
* Suppress duplicate machine state messages to improving OS/2 scrolling
*
* Revision 1.3 1992/12/18 12:05:57 ahd
* Suppress duplicate machine state messages to improving OS/2 scrolling
*
* Revision 1.2 1992/11/22 20:58:55 ahd
* Use strpool to allocate const strings
*
*/
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "lib.h"
#include "hlib.h"
#include "hostable.h"
#include "security.h"
currentfile();
static struct HostTable *hosts = NULL;
static size_t HostElements = 0;
static size_t loadhost( void );
static int hostcmp( const void *a , const void *b );
static size_t localdomainl; /* Length of localdomain */
/*--------------------------------------------------------------------*/
/* c h e c k n a m e */
/* */
/* Perform a search for a single host name */
/* */
/* Rewritten for release 1.10a. The old release had */
/* most of the same logic, but nested it inside the search */
/* loop; adding new cases (specifically, the wildcard domain */
/* search) was difficult. This version is slower because it */
/* makes multiple passes through the host table, but this */
/* isn't really performance code for a small (under 100 hosts) */
/* table. ahd 26 April 1991 */
/* */
/* Note because we save the arguments and use a static variable */
/* to save the result of searches, this function is not */
/* recursive! */
/*--------------------------------------------------------------------*/
struct HostTable *checkname(const char *name)
{
char hostname[MAXADDR]; /* Local copy of name to process */
char *period; /* Pointer "." in hostname */
size_t namel; /* Length of the name input */
size_t column; /* Length of the name input */
static char savename[MAXADDR] = "";
/* Saved copy of name to make function
reducible */
static struct HostTable *hostz;
/*--------------------------------------------------------------------*/
/* Validate the argument */
/*--------------------------------------------------------------------*/
if ((name == NULL) || ((namel = strlen(name)) == 0))
{
printmsg(0,"checkname: Invalid (missing) hostname passed");
panic();
return NULL; /* Never executed */
}
/*--------------------------------------------------------------------*/
/* If same argument as last time, return same result; otherwise */
/* save input for next pass */
/*--------------------------------------------------------------------*/
if (equal(name, savename))
return hostz;
strcpy( savename, name); /* Save for next pass */
/*--------------------------------------------------------------------*/
/* Search for the full name */
/*--------------------------------------------------------------------*/
if ((hostz = searchname(name, MAXADDR)) != BADHOST)
return hostz;
/*--------------------------------------------------------------------*/
/* If the name already has the local domain attached, search for */
/* the host name without the domain. */
/*--------------------------------------------------------------------*/
column = namel - localdomainl;
if ((namel > localdomainl) && equal(E_localdomain, &name[column]) &&
(name[ column - 1] == '.'))
{
if ((hostz = searchname(name,column-1 )) != BADHOST)
return hostz;
} /* if */
/*--------------------------------------------------------------------*/
/* Search for the name in the local domain */
/*--------------------------------------------------------------------*/
if ((namel + localdomainl + 2) < MAXADDR)
{
sprintf(hostname,"%s.%s",name,E_localdomain);
if ((hostz = searchname(hostname, MAXADDR)) != BADHOST)
return hostz;
} /* if */
/*--------------------------------------------------------------------*/
/* If a simple name and not found, return search for truncated */
/* UNIX name. */
/*--------------------------------------------------------------------*/
if ( strchr(name,'.') == NULL )
return checkreal( name );
/*--------------------------------------------------------------------*/
/* Perform a wildcard domain name search */
/*--------------------------------------------------------------------*/
period = (char *) name; /* Begin at front of name */
while( period != NULL )
{
sprintf( hostname,(*period == '.') ? "*%s" : "*.%s",period);
/* We add the missing period for the
first pass through the loop */
if ((hostz = searchname(hostname, MAXADDR)) != BADHOST)
return hostz;
period = strchr(++period,'.'); /* Not found, search for next
higher domain */
}
/*--------------------------------------------------------------------*/
/* We didn't find the host. Return failure to caller */
/*--------------------------------------------------------------------*/
return BADHOST;
} /* checkname */
/*--------------------------------------------------------------------*/
/* c h e c k r e a l */
/* */
/* Perform a search for a real (connected) simple host name */
/*--------------------------------------------------------------------*/
struct HostTable *checkreal(const char *name)
{
size_t namel = max( strlen(name), HOSTLEN);
struct HostTable *hostp = searchname( name, namel );
/*--------------------------------------------------------------------*/
/* If we didn't find the host, return failure */
/*--------------------------------------------------------------------*/
if ((hostp == BADHOST) || (hostp->hstatus >= nocall))
return hostp; /* Return raw information */
else
return BADHOST; /* Not a real host, invalid for our
purposes */
} /* searchreal */
/*--------------------------------------------------------------------*/
/* s e a r c h n a m e */
/* */
/* Look up a system name in our systems (L.sys) file. */
/* Only the first 7 characters of a system name is significant. */
/*--------------------------------------------------------------------*/
struct HostTable *searchname(const char *name, const size_t namel)
{
int lower;
int upper;
/*------------------------------------------------------------------*/
/* Initialize the host name table if needed */
/*------------------------------------------------------------------*/
if (HostElements == 0) /* host table initialized yet? */
HostElements = loadhost(); /* No --> load it */
lower = 0;
upper = HostElements - 1;
while ( lower <= upper )
{
int midpoint = (lower + upper) / 2;
int hit;
/*--------------------------------------------------------------------*/
/* Compare for up to the specified length of the host name, but */
/* never less than the length of the item we are comparing it */
/* to. In other words, the search key can be shorter than the */
/* table entry for a simple host name. */
/* */
/* This mostly affects simple host names, as domain names */
/* have a Very Large Number (VLN) passed into to insure we */
/* compare the entire length of the name. */
/*--------------------------------------------------------------------*/
hit = strnicmp(name,hosts[midpoint].hostname,namel);
if (hit > 0)
lower = midpoint + 1;
else if ((hit < 0) || (strlen(hosts[midpoint].hostname) > namel))
upper = midpoint - 1;
else {
printmsg(8,"searchname: Looking for \"%s\" of length %d,\
found \"%s\"",
name, namel, hosts[midpoint].hostname);
return &hosts[midpoint];
}
}
/*--------------------------------------------------------------------*/
/* We didn't find the host. Return failure to caller */
/*--------------------------------------------------------------------*/
printmsg(8,"searchname: Looking for \"%s\", did not find it",
name);
return BADHOST;
} /* searchname */
/*--------------------------------------------------------------------*/
/* n e x t h o s t */
/* */
/* Returns next host in table with requested attribute */
/*--------------------------------------------------------------------*/
struct HostTable *nexthost( const boolean start )
{
static size_t current = 0;
if (HostElements == 0) /* host table initialized yet? */
HostElements = loadhost(); /* No --> load it */
if (start)
current = 0;
else
current ++;
while ( current < HostElements )
{
if (hosts[current].hstatus >= nocall)
return &hosts[current];
else
current++;
}
return BADHOST;
} /* nexthost */
/*--------------------------------------------------------------------*/
/* i n i t h o s t */
/* */
/* Intializes a host table entry for for loadhost */
/*--------------------------------------------------------------------*/
struct HostTable *inithost(char *name)
{
size_t hit = HostElements;
size_t element = 0;
static size_t max_elements = 32; /* This is automatically
raised if we run out of room */
if (hosts == NULL)
{
hosts = calloc(max_elements, sizeof(*hosts));
printmsg(5,"inithost: Allocated room for %d host entries",
max_elements);
}
else if ( max_elements == HostElements )
{
max_elements = max_elements * 2;
hosts = realloc(hosts , max_elements * sizeof(*hosts));
printmsg(5,"inithost: reallocated room for %d host entries",
max_elements);
}
checkref(hosts);
/*--------------------------------------------------------------------*/
/* Add the host to the table. Note that we must add the host */
/* to the table ourselves (rather than use lsearch) because we */
/* must make a copy of the string; the *token we use for the */
/* search is in the middle of our I/O buffer! */
/*--------------------------------------------------------------------*/
while ( element < hit )
{
if (equali( hosts[element].hostname , name ))
hit = element;
else
element++;
}
/*--------------------------------------------------------------------*/
/* If a new element, initialize the block */
/*--------------------------------------------------------------------*/
if (hit == HostElements)
{
memset( &hosts[hit] , 0, sizeof hosts[hit] );
hosts[hit].hostname = newstr(name);
checkref( hosts[hit].hostname );
hosts[hit].anylogin = TRUE; /* Allow generic login by default */
HostElements ++ ;
} /* if */
return &hosts[hit];
} /* inithost */
/*--------------------------------------------------------------------*/
/* l o a d h o s t */
/* */
/* Initializes table of known host names for checkname */
/*--------------------------------------------------------------------*/
static size_t loadhost()
{
FILE *ff;
char buf[BUFSIZ];
char *token;
char s_systems[FILENAME_MAX]; /* full-name of systems file */
size_t hit;
struct HostTable *hostp;
/*--------------------------------------------------------------------*/
/* Validate the domain name */
/*--------------------------------------------------------------------*/
token = strrchr(E_domain,'.');
if (token == NULL)
{
printmsg(0,"Domain name \"%s\" is invalid, missing period",E_domain);
panic();
}
/*--------------------------------------------------------------------*/
/* Load the local host information */
/*--------------------------------------------------------------------*/
hostp = inithost(E_nodename);
hostp->hstatus = localhost;
hostp->realname = E_nodename; /* Don't let user alias our system
name */
/*--------------------------------------------------------------------*/
/* Now do the local domain information */
/*--------------------------------------------------------------------*/
hostp = inithost(E_domain);
if (hostp->via == NULL ) /* Not initialized? */
hostp->via = E_nodename; /* Correct --> Route via local */
else
panic(); /* "Houston, we a have problem" -
Apollo 13 */
hostp->realname = E_nodename;
/*--------------------------------------------------------------------*/
/* If we allow anonymous UUCP, load the dummy host we use for */
/* connections to such hosts */
/*--------------------------------------------------------------------*/
if ( E_anonymous != NULL )
{
hostp = inithost( ANONYMOUS_HOST );
hostp->hstatus = nocall;
hostp->via = E_nodename;
hostp->hstats = malloc( sizeof *(hostp->hstats) );
checkref( hostp->hstats );
memset( hostp->hstats, 0, sizeof *(hostp->hstats) );
} /* if */
/*--------------------------------------------------------------------*/
/* Load names from the systems file */
/*--------------------------------------------------------------------*/
mkfilename(s_systems, E_confdir, SYSTEMS);
ff = FOPEN(s_systems, "r",TEXT_MODE);
if (ff == NULL)
{
printerr(s_systems);
panic();
}
while (! feof(ff))
{
if (fgets(buf,BUFSIZ,ff) == NULL) /* Try to read a line */
break; /* Exit if end of file */
token = strtok(buf,WHITESPACE);
if (token == NULL) /* Any data? */
continue; /* No --> read another line */
if (token[0] == '#')
continue; /* Line is a comment; loop again */
if ( equal( token, E_nodename ))
{
printmsg(0,"Error: Local host %s must not be in SYSTEMS file",
E_nodename );
panic();
}
hostp = inithost(token);
if (hostp->hstatus == phantom)
{
hostp->hstatus = nocall;
hostp->hstats = malloc( sizeof *(hostp->hstats) );
checkref( hostp->hstats );
memset( hostp->hstats, 0, sizeof *(hostp->hstats) );
}
} /* while */
fclose(ff);
/*--------------------------------------------------------------------*/
/* Now the load the routing file, if any. */
/*--------------------------------------------------------------------*/
mkfilename(s_systems, E_confdir, PATHS);
if ((ff = FOPEN(s_systems, "r",TEXT_MODE)) != NULL)
{
while (! feof(ff))
{
boolean freeit = FALSE;
if (fgets(buf,BUFSIZ,ff) == NULL) /* Try to read a line */
break; /* Exit if end of file */
token = strtok(buf,WHITESPACE);
if (token == NULL) /* Any data? */
continue; /* No --> read another line */
if (*token == '#')
continue; /* Line is a comment; loop again */
hostp = inithost(token);
token = strtok(NULL,WHITESPACE);
if ( token == NULL )
{
printmsg(0,"loadhost: Missing path name for host \"%s\"",
hostp->hostname);
freeit = TRUE;
}
/*--------------------------------------------------------------------*/
/* Gate way */
/*--------------------------------------------------------------------*/
else if (equal(token,"|"))
{
token = strtok(NULL,"\n");
if (( hostp->via != NULL ) || ( token == NULL ))
freeit = TRUE;
else {
hostp->hstatus = gatewayed;
while(isspace( *token )) /* Drop leading white space only */
token++;
if (*token == '\0') /* Empty string? */
freeit = TRUE; /* Yes --> Flag for error */
else
hostp->via = token = newstr(token);
} /* else if */
if ( freeit )
printmsg(0,"loadhost: Invalid/duplicate gateway for \"%s\"",
hostp->hostname );
} /* else if */
/*--------------------------------------------------------------------*/
/* Alias */
/*--------------------------------------------------------------------*/
else if (equal(token,"="))
{
token = strtok(NULL,WHITESPACE);
if (( hostp->realname == NULL ) && (token != NULL))
hostp->realname = token = newstr( token );
else {
printmsg(0,"loadhost: Invalid/duplicate alias of \"%s\"",
hostp->hostname );
freeit = TRUE;
} /* else */
} /* else if (equal(token,"=")) */
/*--------------------------------------------------------------------*/
/* Routing entry */
/*--------------------------------------------------------------------*/
else {
if ( hostp->via == NULL )
hostp->via = token = newstr( token );
else {
printmsg(0,"loadhost: Invalid/duplicate route for \"%s\"",
hostp->hostname );
freeit = TRUE;
} /* else */
} /* else */
if ( ! freeit )
{
checkref( token );
if (*token == '*') /* Wildcard on right side? */
{
printmsg(0,
"loadhost: Wildcard \"%s\" not allowed for real name of host \"%s\"",
token, hostp->hostname);
freeit = TRUE;
} /* if (*token == '*') */
} /* if ( ! freeit ) */
if ( freeit )
{
if ( hostp->hstatus == phantom )
HostElements--; /* Ignore the routing entry */
}
} /* end while */
fclose(ff);
}
else {
if ( debuglevel > 2 )
perror( s_systems );
}
/*--------------------------------------------------------------------*/
/* Provide default for fromdomain */
/*--------------------------------------------------------------------*/
if (E_fdomain != NULL) /* If fromdomain provided ... */
{
hostp = inithost(E_fdomain);
if (hostp->via == NULL) /* Uninitialized? */
hostp->via = E_mailserv; /* Yes --> Use default route */
}
else
E_fdomain = E_domain; /* Use domain as fromdomain */
/*--------------------------------------------------------------------*/
/* Shrink the table to whatever we actually need, then sort it */
/*--------------------------------------------------------------------*/
hosts = realloc(hosts, HostElements * sizeof(*hosts));
checkref(hosts);
qsort(hosts, HostElements ,sizeof(hosts[0]) , hostcmp);
/*--------------------------------------------------------------------*/
/* If the user did not define a local domain, then generate one */
/* based on our own domain name; the generated name will either */
/* be of the format ".a.b.c" (incuding the trailing period) or */
/* a null string. */
/*--------------------------------------------------------------------*/
if ( E_localdomain == NULL )
{
E_localdomain = strchr(E_domain,'.');
if (E_localdomain == NULL)
E_localdomain = "UUCP";
else {
E_localdomain ++; /* Step past the period */
if ( !equal(E_localdomain, "UUCP" ) &&
(strchr( E_localdomain, '.' ) == NULL ))
/* Implied single level domain name? */
E_localdomain = E_domain;
/* Impossible, use both parts of name */
} /* else */
printmsg(3,"loadhost: local domain defined as \"%s\"",
E_localdomain);
} /* if */
localdomainl = strlen(E_localdomain);
/*--------------------------------------------------------------------*/
/* Amend for the sin of typing the domain wrong in the sample */
/* files for the old releases of UUPC/extended. */
/*--------------------------------------------------------------------*/
if (equal(E_localdomain,"UUPC"))
{
printmsg(0,"inithost: UUPC is an invalid domain name! "
"Change it to UUCP");
panic();
}
/*--------------------------------------------------------------------*/
/* Display the final table */
/*--------------------------------------------------------------------*/
for (hit = 0; hit < HostElements; hit++)
{
printmsg(8,"loadhost: entry[%02d] %-20s\tvia %s\talias %s",
hit,
hosts[hit].hostname,
(hosts[hit].via == NULL) ? "(self)" : hosts[hit].via,
(hosts[hit].realname == NULL)
? "(self)" : hosts[hit].realname);
} /* for */
/*--------------------------------------------------------------------*/
/* Return to caller */
/*--------------------------------------------------------------------*/
return (HostElements) ;
} /*loadhost*/
/*--------------------------------------------------------------------*/
/* h o s t c m p */
/* */
/* Accepts indirect pointers to two strings and compares */
/* them using stricmp (case insensitive string compare) */
/*--------------------------------------------------------------------*/
int hostcmp( const void *a , const void *b )
{
return stricmp(((struct HostTable*) a)->hostname,
((struct HostTable*) b)->hostname);
} /*hostcmp*/